<script setup lang="ts">
import injectionKeys from "@/injectionKeys";
import { computed, inject, onMounted, PropType, watch } from "vue";
import { useListResources } from "@/composables/useListResources";
import type { Option } from "@/wds/WdsSelect.vue";
import type { WriterApplication } from "@/writerTypes";
import WdsTextInput from "@/wds/WdsTextInput.vue";
import { defineAsyncComponentWithLoader } from "@/utils/defineAsyncComponentWithLoader";

const WdsSelect = defineAsyncComponentWithLoader({
	loader: () => import("@/wds/WdsSelect.vue"),
});

const wf = inject(injectionKeys.core);

const emit = defineEmits<{
	(event: "selected-data", data: WriterApplication | undefined): void;
}>();

defineProps({
	enableMultiSelection: { type: Boolean, required: false },
});

const currentValue = defineModel({
	type: [String, Array] as PropType<string | string[]>,
	required: true,
});

const {
	load: loadApps,
	data: apps,
	isLoading,
} = useListResources<WriterApplication>(wf, "applications");

onMounted(loadApps);

function getAppType(app: WriterApplication) {
	switch (app.type) {
		case "chat":
			return "Chat app";
		case "framework":
			return "Framework";
		case "generation":
			return "Text generation";
		case "research":
			return "Research assistant";
	}
}

const options = computed(() =>
	apps.value
		.map<Option>((app) => ({
			label: app.name,
			value: app.id,
			detail: [getAppType(app), app.status].join(` · `),
		}))
		.sort((a, b) => a.label.localeCompare(b.label)),
);

const currentValueStr = computed<string>({
	get() {
		if (currentValue.value === undefined) return "";

		return typeof currentValue.value === "string"
			? currentValue.value
			: currentValue.value.join(",");
	},
	set(value: string) {
		currentValue.value = value.split(",");
	},
});

const selectedData = computed(() => {
	if (currentValue.value === undefined) return undefined;

	// Application select should never support multi-selection
	if (typeof currentValue.value !== "string") return undefined;

	return apps.value.find((g) => g.id === currentValue.value);
});

watch(
	() => currentValue.value,
	() => {
		// Ignore empty states where apps haven't loaded yet
		if (!apps.value.length) return;

		const picked = apps.value.find((a) => a.id === currentValue.value);
		emit("selected-data", picked);
	},
);

defineExpose({ selectedData });
</script>

<template>
	<div class="BuilderGraphSelect--text">
		<WdsSelect
			v-if="apps.length > 0 || isLoading"
			v-model="currentValue"
			:options="options"
			hide-icons
			enable-search
			:loading="isLoading"
			:enable-multi-selection="enableMultiSelection"
		/>
		<WdsTextInput v-else v-model="currentValueStr" />
	</div>
</template>

<style scoped>
.BuilderGraphSelect--text {
	width: 100%;
	display: flex;
	gap: 12px;
	align-items: center;
}
</style>
